﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: ScaleOutSettingsViewModel
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{
    public class ScaleOutSettingsViewModel : TreeViewItemViewModel, IDataErrorInfo, IProduceValidationResults
    {
        private readonly VmRoleResourceDefinitionViewModel vmRoleResourceDefinitionViewModel;
        private readonly ScaleOutSettings scaleOutSettings;   

        private IntParameterizableProperty initialInstanceCount;
        private IntParameterizableProperty maximumInstanceCount;
        private IntParameterizableProperty minimumInstanceCount;
        private IntParameterizableProperty upgradeDomainCount;

        public static class PropertyNames
        {
            public const string Summary = "Summary";          
            public const string InitialInstanceCount = "InitialInstanceCount";
            public const string MaximumInstanceCount = "MaximumInstanceCount";
            public const string MinimumInstanceCount = "MinimumInstanceCount";
            public const string UpgradeDomainCount = "UpgradeDomainCount";
        }

        public ScaleOutSettingsViewModel(
            ScaleOutSettings scaleOutSettings,
            VmRoleResourceDefinitionViewModel resourceDefinitionViewModel)
            : base(resourceDefinitionViewModel, true)
        {
            if (scaleOutSettings == null)
            {
                scaleOutSettings = new ScaleOutSettings();
            }
            this.scaleOutSettings = scaleOutSettings;
            this.vmRoleResourceDefinitionViewModel = resourceDefinitionViewModel;
            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();         
        }

        public string Summary
        {
            get
            {                
                return "Scale Out";
            }
        }

        public IntParameterizableProperty InitialInstanceCount
        {
            get
            {
                if (this.initialInstanceCount == null)
                {
                    Func<string> paramValueGetter = () => this.scaleOutSettings.InitialInstanceCount;
                    Action<string> paramValueSetter = delegate(string value) { this.scaleOutSettings.InitialInstanceCount = value; };
                    Func<string> autoParamNameGetter = () => ParametersViewModel.VMRolePrefix + PropertyNames.InitialInstanceCount;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultInitialValue = "1",
                        DefaultEnglishLabelText = "Initial Instance Count"
                    };

                    this.initialInstanceCount = new IntParameterizableProperty(
                        PropertyNames.InitialInstanceCount,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Initial Instance Count",
                        this.vmRoleResourceDefinitionViewModel.ResourceDefinitionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.initialInstanceCount;
            }
        }

        public IntParameterizableProperty MaximumInstanceCount
        {
            get
            {
                if (this.maximumInstanceCount == null)
                {
                    Func<string> paramValueGetter = () => this.scaleOutSettings.MaximumInstanceCount;
                    Action<string> paramValueSetter = delegate(string value) { this.scaleOutSettings.MaximumInstanceCount = value; };
                    Func<string> autoParamNameGetter = () => ParametersViewModel.VMRolePrefix + PropertyNames.MaximumInstanceCount;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultInitialValue = "1",
                        DefaultEnglishLabelText = "Maximum Instance Count"
                    };

                    this.maximumInstanceCount = new IntParameterizableProperty(
                        PropertyNames.MaximumInstanceCount,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Maximum Instance Count",
                        this.vmRoleResourceDefinitionViewModel.ResourceDefinitionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.maximumInstanceCount;
            }
        }

        public IntParameterizableProperty MinimumInstanceCount
        {
            get
            {
                if (this.minimumInstanceCount == null)
                {
                    Func<string> paramValueGetter = () => this.scaleOutSettings.MinimumInstanceCount;
                    Action<string> paramValueSetter = delegate(string value) { this.scaleOutSettings.MinimumInstanceCount = value; };
                    Func<string> autoParamNameGetter = () => ParametersViewModel.VMRolePrefix + PropertyNames.MinimumInstanceCount;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultInitialValue = "1",
                        DefaultEnglishLabelText = "Minimum Instance Count"
                    };

                    this.minimumInstanceCount = new IntParameterizableProperty(
                        PropertyNames.MinimumInstanceCount,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Minimum Instance Count",
                        this.vmRoleResourceDefinitionViewModel.ResourceDefinitionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.minimumInstanceCount;
            }
        }

        public IntParameterizableProperty UpgradeDomainCount
        {
            get
            {
                if (this.upgradeDomainCount == null)
                {
                    Func<string> paramValueGetter = () => this.scaleOutSettings.UpgradeDomainCount;
                    Action<string> paramValueSetter = delegate(string value) { this.scaleOutSettings.UpgradeDomainCount = value; };
                    Func<string> autoParamNameGetter = () => ParametersViewModel.VMRolePrefix + PropertyNames.UpgradeDomainCount;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Number,
                        DefaultInitialValue = "2",
                        DefaultEnglishLabelText = "Upgrade Domain Count"
                    };

                    this.upgradeDomainCount = new IntParameterizableProperty(
                        PropertyNames.UpgradeDomainCount,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Int,
                        "Upgrade Domain Count",
                        this.vmRoleResourceDefinitionViewModel.ResourceDefinitionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.upgradeDomainCount;
            }
        }
        
        public string this[string propertyName]
        {
            get
            {
                string error = null;
                int minCount, maximumCount;
                switch (propertyName)
                {
                    case PropertyNames.InitialInstanceCount:
                        if (this.initialInstanceCount != null && !this.initialInstanceCount.IsParameterized)
                        {
                            int initCount;
                            if (Int32.TryParse(this.initialInstanceCount.PropertyValue, out initCount))
                            {
                                 if (initCount < 0)
                                 {
                                     error = "Cannot specify negative value";                                    
                                 }
                                 else
                                 {
                                     if (Int32.TryParse(this.maximumInstanceCount.PropertyValue, out maximumCount) && Int32.TryParse(this.minimumInstanceCount.PropertyValue, out minCount))
                                     {
                                         if (initCount < minCount || initCount > maximumCount)
                                         {
                                             error = "Initial instance count must be between min and max";                                           
                                         }
                                     }
                                 }
                                 
                            }
                            else
                            {
                                error = "Invalid intger";
                            }
                        }
                        break;
                    case PropertyNames.MaximumInstanceCount:
                        if (this.maximumInstanceCount != null && !this.maximumInstanceCount.IsParameterized)
                        {
                            if (Int32.TryParse(this.maximumInstanceCount.PropertyValue, out maximumCount))
                            {
                                if (maximumCount < 0)
                                {
                                    error = "Cannot specify negative value";
                                }
                                else
                                {
                                    if (Int32.TryParse(this.minimumInstanceCount.PropertyValue, out minCount))
                                    {
                                        if (maximumCount < minCount)
                                        {
                                            error = "Incorrect min <max  for ScaleOutSettings";
                                        }
                                    }
                                }
                            }
                            else
                            {
                                error = "Invalid intger";
                            }
                        }
                        break;
                    case PropertyNames.MinimumInstanceCount:
                        if (this.minimumInstanceCount != null && !this.minimumInstanceCount.IsParameterized)
                        {
                            if (Int32.TryParse(this.minimumInstanceCount.PropertyValue, out minCount))
                            {
                                if (minCount < 0)
                                {
                                    error = "Cannot specify negative value";
                                }
                                else
                                {
                                    if (Int32.TryParse(this.maximumInstanceCount.PropertyValue, out maximumCount))
                                    {
                                        if (maximumCount < minCount)
                                        {
                                            error = "Incorrect min <max  for ScaleOutSettings";
                                        }
                                    }
                                }
                            }
                            else
                            {
                                error = "Invalid intger";
                            }
                        }
                        break;
                    case PropertyNames.UpgradeDomainCount:
                        if (this.upgradeDomainCount != null && !this.upgradeDomainCount.IsParameterized)
                        {
                            int udCount;
                            if (Int32.TryParse(this.upgradeDomainCount.PropertyValue, out udCount))
                            {
                                if (udCount < 0)
                                {
                                    error = "Cannot specify negative value";
                                }                               
                            }
                            else
                            {
                                error = "Invalid intger";
                            }
                        }
                        break;
                }            
                return error;
            }
        }

        public string Error { get; set; }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            this.IsExpanded = true;
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error            
        } 
    }
}
